home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1999 March
/
EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso
/
earcd
/
devel
/
vbcc-68k-src
/
machines
/
amiga68k
/
libsrc
/
fd2lib.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-01-01
|
26KB
|
1,002 lines
/* fd2lib by Volker Barthelmann */
/* rework 09/96 by Johnny Teveßen <j.tevessen@line.org> */
/* V1.4 14-Jul-98 phx: ##abi support. */
/* V1.5 04-Oct-98 phx: FPU register support. */
/* Allow function names > 28 chars. */
#define NDEBUG
#ifdef _DCC
# define CTYPE_NEAR
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
/* AmigaOS version string. Doesn't hurt... */
const char VersTag[] = "\0$VER: fd2lib 1.5 (04.10.98)";
char *clibname,*clibtext;
#define MAXLINELEN 1000
#define BUFFEREDLEN 16384 /* 1024 is standard */
#define NUMREGS 24
static const char *regnames[NUMREGS] =
{
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"fp0","fp1","fp2","fp3","fp4","fp5","fp6","fp7"
};
enum
{
A0=0, A1, A2, A3, A4, A5, A6, A7,
D0 , D1, D2, D3, D4, D5, D6, D7,
FP0 ,FP1,FP2,FP3,FP4,FP5,FP6,FP7
};
#define SMALLCODE 1
#define SMALLDATA 2
#define FASTCALL 4
#define NEWNOTATE 8
#define VARGSLOGIC 16
#define DEBUG 32
#ifndef TRUE
typedef short BOOL;
# define TRUE 1
# define FALSE 0
#endif
#ifndef NULL
# define NULL ((void *)0L)
#endif
#ifdef __GNUC__
# define gnuspec(x) x
#else
# define gnuspec(x)
#endif
#define NORETURN gnuspec(__attribute__ ((noreturn)))
static const char *varargs[] =
{
#include "vargs.h"
NULL, NULL
};
int get_type(char *dest,const char *p,const char *fname,int arg)
{
int nest,carg,l=strlen(fname);const char *last=p,*m,*m2;
if(arg<0) return 0;
while(*p){
if(*p==';'||*p=='\n')
{last=p;while(isspace((unsigned char)*last)) last++;}
if(!strncmp(p,fname,l)){
m=p;m2=p-1;p+=l;
while(isspace((unsigned char)*p)) p++;
if(*p!='('||isalnum((unsigned char)*m2)){
continue;
}else{
if(arg==0){
memcpy(dest,last,m-last);
dest[m-last]=0;
return 1;
}
p++;carg=1;nest=0;
while(1){
while(isspace((unsigned char)*p)) p++;
if(*p==')'||*p==0)
return 0;
if(carg==arg){
while(nest!=0||(*p!=','&&*p!=')')){
if(!*p) return 0;
if(*p=='(') nest++;
if(*p==')') nest--;
*dest++=*p++;
}
*dest=0;
return 1;
}
while(nest!=0||(*p!=','&&*p!=')')){
if(!*p) return 0;
if(*p=='(') nest++;
if(*p==')') nest--;
p++;
}
p++;
carg++;
}
}
}
p++;
}
return 0;
}
static void ExitFailure(const char *, const char *) NORETURN;
static void ExitFailure(const char *cause, const char *insertme)
{
fprintf(stderr, cause, insertme);
exit(EXIT_FAILURE);
}
static void check(const char *ptr)
{
if(!*ptr)
{
ExitFailure("Unexpected EOL\n", NULL);
}
}
static void warnhim(int linenr, const char *format, ...) gnuspec(__attribute__ ((format (printf, 2, 3))));
static void warnhim(int linenr, const char *format, ...)
{
char linebuf[250];
va_list vl;
va_start(vl,format);
vsprintf(linebuf, format, vl);
va_end(vl);
fprintf(stderr, "Warning line %d: %s\n", linenr, linebuf);
}
static FILE *OpenLVO(const char *name, const char *outdir,
const char *outform)
{
FILE *lvos;
char lvoname[MAXLINELEN];
strcpy(lvoname, outdir);
if(name)
{
char *k = (char *)name, *p;
int lvonamlen;
if((p = strrchr(k, '/')) != NULL) k = p + 1;
if((p = strrchr(k, ':')) != NULL) k = p + 1;
strcat(lvoname, k);
lvonamlen = strlen(lvoname);
if((lvonamlen > 7) && !strcmp(lvoname+lvonamlen-7, "_lib.fd"))
{
lvoname[lvonamlen-7] = '\0';
}
else if((lvonamlen > 3) && !strcmp(lvoname+lvonamlen-3, ".fd"))
{
lvoname[lvonamlen-3] = '\0';
}
strcat(lvoname, "_lvo.s");
}
else
{
strcat(lvoname, "fd_lvo.s");
}
printf(outform, lvoname, lvoname, lvoname);
lvos = fopen(lvoname, "w");
return(lvos);
}
static void ProcessFD(const char *name, int mode,
const char *outdir, const char *outform)
{
FILE *fd, *lvos;
FILE *out;
int offset = 0, i, j, count, savecount, fsavecount;
char function[80], tmpfuncnam[80], ff[MAXLINELEN+8], base[50];
char line[MAXLINELEN], lastchar='A';
register char *p;
char *functionp;
int reg[NUMREGS], loops, linenr = 0;
BOOL public = -1; /* Why FALSE? */
BOOL abim68k = TRUE;
BOOL fpregs;
char typ[1024];
/* "-1" is the initial value for "public". It means:
** no statement yet.
*/
*function = *base = *line = '\0';
if(name) fd = fopen(name, "r");
else fd = stdin;
if(!fd) ExitFailure("Could not open `%s'\n", name);
setvbuf(fd, NULL, _IOFBF, BUFFEREDLEN); /* maybe _IOLBF? */
if(!(lvos = OpenLVO(name, outdir, outform)))
ExitFailure("Could not create lvo file\n", NULL);
setvbuf(lvos, NULL, _IOFBF, BUFFEREDLEN);
for(;;)
{
char *k;
if(!fgets(line, MAXLINELEN-1, fd)) ExitFailure("Unexpected EOF\n", NULL);
linenr ++;
if((*line == '*') || !*line) continue;
switch(*line + line[2]) {
case ('#'+'a'):
if (!strncmp(line, "##abi", 5)) { /* ##abi */
p = line+5;
while (isspace((unsigned)*p)) p++;
if (!strncmp(p, "M68k", 4)) {
abim68k = TRUE;
if(mode & DEBUG)
printf("ABI set to M68k\n");
}
else if (!strncmp(p, "PPC", 3)) {
abim68k = FALSE;
if(mode & DEBUG)
printf("ABI set to PPC (WarpOS)\n");
}
else
warnhim(linenr, "Unknown ##abi specification ignored!");
continue;
}
break;
case ('#'+'b'):
if(!strncmp(line, "##base", 6)) {
if(*base) warnhim(linenr, "##base detected more than once!");
p = line+6; while(isspace(*p)) p++;
k = base ; while(isgraph(*p)) *k++ = *p++;
*k = '\0';
if(mode & DEBUG) printf("Base set to `%s'\n", base);
continue;
}
if(!strncmp(line, "##bias", 6)) {
p = line+6; while(isspace(*p)) p++;
sscanf(p, "%i", &offset);
if(mode & DEBUG) printf("Bias set to -%d\n", offset);
continue;
}
break;
case ('#'+'p'):
if(!strncmp(line, "##public", 8)) {
if(public == TRUE) warnhim(linenr, "##public after ##public detected!");
else public = TRUE;
if(mode & DEBUG) printf("Turned on public mode at bias -%d\n", offset);
continue;
}
if(!strncmp(line, "##private", 9)) {
if(public == FALSE) warnhim(linenr, "##private after ##private detected!");
else public = FALSE;
if(mode & DEBUG) printf("Turned off public mode at bias -%d\n", offset);
continue;
}
break;
case ('#'+'e'):
if(!strncmp(line, "##end", 5)) return;
break;
}
if(*line == '#') {
warnhim(linenr, "Unknown directive: `%s'!", line);
continue;
}
if(!public || !abim68k) {
offset += 6;
continue;
}
if(public == -1) {
warnhim(linenr, "Neither ##public nor ##private specified yet. Assuming ##public.");
public = TRUE;
}
functionp = function;
for(loops=0; loops<=1; loops++) {
int saveoffset;
char *p = line; char *k = functionp;
while(isspace(*p)) p++;
if(!loops)
{
while((*p != '(') && *p) *k++ = *p++;
check(p);
*k = '\0';
fprintf(lvos, "_LVO%s\tequ\t-%d\n"
"\txdef\t_LVO%s\n",
functionp, offset, functionp);
}
else
{
while((*p != '(') && *p) p++;
check(p);
}
if(mode & DEBUG)
printf("function=%s, loops=%d\n", functionp, loops);
/* This should be AMIGA OS only: */
if (strlen(functionp) > 28) {
sprintf(ff, "%s%.27s%c.s", outdir, functionp, lastchar);
warnhim(linenr,"File name %s.s is too long for AmigaOS file system."
" Changed into: %.27s%c.s",functionp,functionp,lastchar);
if (lastchar=='Z')
lastchar = 'A';
else
lastchar++;
}
else
sprintf(ff, "%s%s.s", outdir, functionp);
/* Open function stub source file */
printf(outform, ff, ff, ff);
out = fopen(ff, "w");
if(!out) ExitFailure("Could not create <%s>\n", functionp);
setvbuf(out, NULL, _IOFBF, BUFFEREDLEN);
/* Set all registers to 'unused' */
for(i=0; i<NUMREGS; i++) reg[i] = 0;
/* Skip argument names */
while((*p!=')') && *p) p++;
check(p);
p++;
if(clibtext&&!loops){
if(!get_type(typ,clibtext,functionp,0)) strcpy(typ,"error");
printf("%s __%s(",typ,functionp);
}
/* Search for beginning of register list */
while((*p!='(') && *p) p++;
check(p);
p++;
/* Scan register list */
count = savecount = fsavecount = 0;
fpregs = FALSE;
while((*p!=')') && *p) {
char c = *p;
/* Check whether register description is valid */
if (!((c=='a' || c=='A' || c=='d' || c=='D') &&
(p[1]>='0' && p[1]<='7')) &&
!((c=='f' || c=='F') && (p[1]=='p' || p[1]=='P') &&
(p[2]>='0' && p[2]<='7')))
ExitFailure("Bad register description\n", NULL);
/* Convert description to internal enum format */
/* Corrected: 'A' was not recognized */
if (c=='a' || c=='A')
j = p[1] - '0';
else if (c=='d' || c=='D')
j = p[1] - ('0'-8);
else
j = p[2] - ('0'-16);
if(clibtext&&!loops){
if(!get_type(typ,clibtext,functionp,count+1)) strcpy(typ,"error");
printf("__reg(\"%s\") %s,",regnames[j],typ);
}
/* Mark register as used and save its argument counter */
reg[j] = ++count;
/* Increase counter if register has to be saved */
if (j>=FP0) {
if (j>=FP2 && j<=FP7)
fsavecount++;
}
else if (!(j==A0 || j==A1 || j==A6 || j==D0 || j==D1))
savecount++;
/* Search for next register */
if (j >= FP0) {
fpregs = TRUE;
p += 3;
}
else
p += 2;
while(isspace(*p) && *p) p++;
if((*p == '/') || (*p==',')) p++;
else if(*p != ')') ExitFailure("Parse error - ')' expected\n", NULL);
while(isspace(*p) && *p) p++;
check(p);
}
/* Write assembler headers */
if (fpregs) fprintf(out,"\tfpu\t1\n");
if (mode & SMALLDATA) fprintf(out, "\tnear\t%s,-2\n", regnames[A4]);
if (mode & SMALLCODE) fputs ( "\tnear\tcode\n" , out);
if (*base) fprintf(out, "\txref\t%s\n", base);
fprintf(out, "\txdef\t_%s\n"
"\tsection\t\"CODE\",code\n"
"\n"
"_%s:\n",
functionp, functionp);
if(clibtext&&!loops){
int i;
printf("__reg(\"a6\") void *)=\"\\tjsr\\t-%d(a6)\";\n",offset);
printf("#define %s(",functionp);
for(i=1;i<=count;i++){
if(i>1) printf(",");
printf("x%d",i);
}
printf(") __%s(",functionp);
for(i=1;i<=count;i++) printf("(x%d),",i);
printf("%s)\n",base+1);
}
if (fsavecount) {
char c = '\t';
/* number of FPU registers to be saved */
if (!(mode & FASTCALL) && (fsavecount > 1))
fprintf(out,"\tfmovem");
for (i=FP2; i<=FP7; i++) {
if (reg[i]) {
if ((mode & FASTCALL) || (fsavecount == 1)) {
fprintf(out,"\tfmove.x\t%s,-(%s)\n",
regnames[i],regnames[A7]);
}
else {
fprintf(out,"%c%s",c,regnames[i]);
c = '/';
}
}
}
if (!(mode & FASTCALL) && (fsavecount > 1))
fprintf(out,",-(%s)\n",regnames[A7]);
}
if(savecount) {
/* 'savecount' registers have to be saved */
/* Always save library register */
if((mode & FASTCALL) || (savecount == 1))
{
/* Store registers sequential. NEW: Changed that it'll also be
** used if only two (including library register) registers have
** to be stored. That's faster than the original method.
*/
fprintf(out, "\tmove.l\t%s,-(%s)\n", regnames[A6], regnames[A7]);
}
else
{
/* It would be better to set A6 to the end of the list ...
*/
fprintf(out, "\tmovem.l\t%s", regnames[A6]);
}
for(i=A2; i<=D7; i++) {
/* Can start at 2, because 0 and 1 are ignored */
if(reg[i] != 0)
{
switch(i)
{
case D0:
case D1:
break;
case A6:
warnhim(linenr, "Register conflict in `%s' "
"(using libbasereg)!", functionp);
break;
default:
if((mode & FASTCALL) || (savecount == 1))
{
fprintf(out, "\tmove.l\t%s,-(%s)\n",
regnames[i], regnames[A7]);
}
else
{
fprintf(out, "/%s", regnames[i]);
}
break;
}
}
}
if(!((mode & FASTCALL) || (savecount == 1)))
fprintf(out, ",-(%s)\n", regnames[A7]);
}
else
{
/* No registers have to be saved, so just save the register
** where the library base will be stored
*/
fprintf(out, "\tmove.l\t%s,-(%s)\n", regnames[A6], regnames[A7]);
}
/* Load A6 with base NOW, so there's no conflict with SMALLDATA and A4 anymore ... */
if(*base != '\0')
{
if(mode & SMALLDATA)
{
fprintf(out, (mode & NEWNOTATE) ? "\tmove.l\t(%s,%s),%s\n"
: "\tmove.l\t%s(%s),%s\n",
base, regnames[A4], regnames[A6]);
}
else
{
fprintf(out, "\tmove.l\t%s,%s\n", base, regnames[A6]);
}
}
else ExitFailure("No base defined!\n", NULL);
saveoffset = ((savecount+2)<<2) + fsavecount*12;
for(j=1; j<=count; j++) /* Arguments */
{
for(i=0; i<NUMREGS; i++) /* Registers */
{
if(reg[i] == j) /* Argument in THIS register? */
{
if (i >= FP0) {
/* FPU registers fp0-fp7 */
fprintf(out,(mode & NEWNOTATE) ?
"\tfmove.d\t(%d,%s),%s\n" : "\tfmove.d\t%d(%s),%s\n",
saveoffset, regnames[A7], regnames[i]);
saveoffset += 8;
}
else {
/* a0-a5 / d0-d7 */
if ((i>=D7) || (reg[i+1] != j+1)
|| ((loops==1) && (j>=count-1))) {
if(!loops || (j<count)) {
fprintf(out, (mode & NEWNOTATE) ? "\tmove.l\t(%d,%s),%s\n"
: "\tmove.l\t%d(%s),%s\n",
saveoffset, regnames[A7], regnames[i]);
}
else {
/* Varargs */
if(i <= 7) {
/* adress register */
fprintf(out, (mode & NEWNOTATE) ? "\tlea\t(%d,%s),%s\n"
: "\tlea\t%d(%s),%s\n",
saveoffset, regnames[A7], regnames[i]);
}
else {
/* data register */
/* Changed: moveq.l will be forced if possible
** (there are still assemblers that do not do this
** automatically).
*/
fprintf(out, "\tmove%s\t#%d,%s\n" \
"\tadd.l\t%s,%s\n",
(saveoffset <= 127) ? "q" : ".l",
saveoffset, regnames[i],
regnames[A7], regnames[i]);
}
}
}
else {
/* Here no fastcall - slower. :-( */
fprintf(out, (mode & NEWNOTATE) ? "\tmovem.l\t(%d,%s),%s"
: "\tmovem.l\t%d(%s),%s",
saveoffset, regnames[A7], regnames[i]);
while ((i<D7) && (reg[i+1] == j+1)
&& (!loops || (j<count-1))) {
i++; j++;
fprintf(out, "/%s", regnames[i]);
saveoffset += 4;
}
fputc('\n', out);
}
saveoffset += 4;
} /* if FPU regs */
} /* if reg[i]==j */
} /* for i */
} /* for j */
/* Now place the real function call */
fprintf(out, (mode & NEWNOTATE) ? "\tjsr\t(-%d,%s)\n"
: "\tjsr\t-%d(%s)\n",
offset, regnames[A6]);
/* Start restoring registers ... libbasereg first. */
if(!((mode & FASTCALL) || (savecount == 1)))
{
if(!savecount) fprintf(out, "\tmove.l\t(%s)+,%s" , regnames[A7], regnames[A6]);
else fprintf(out, "\tmovem.l\t(%s)+,%s", regnames[A7], regnames[A6]);
}
/* Now the others */
for(i=A2; i<=D7; i++)
{
if((mode & FASTCALL) || (savecount == 1))
{
j = (D7+2) - i; /* swap direction; okay for != 16 regs? */
}
else
{
j = i;
}
if(reg[j])
{
switch(j)
{
case A6:
case D0:
case D1:
break;
default:
if((mode & FASTCALL) || (savecount == 1))
fprintf(out, "\tmove.l\t(%s)+,%s\n",
regnames[A7], regnames[j]);
else
fprintf(out, "/%s", regnames[j]);
break;
}
}
}
/* If fastcall was used, a6 was put first. So we pop it last. */
if((mode & FASTCALL) || (savecount == 1))
{
fprintf(out, "\tmove.l\t(%s)+,%s", regnames[A7], regnames[A6]);
}
if (fsavecount) {
char c = ',';
/* number of FPU registers to be saved */
if (!(mode & FASTCALL) && (fsavecount > 1))
fprintf(out,"\n\tfmovem\t(%s)+",regnames[A7]);
for (i=FP2; i<=FP7; i++) {
if (reg[i]) {
if ((mode & FASTCALL) || (fsavecount == 1)) {
fprintf(out,"\n\tfmove.x\t(%s)+,%s",
regnames[A7],regnames[i]);
}
else {
fprintf(out,"%c%s",c,regnames[i]);
c = '/';
}
}
}
}
/* Return from subroutine */
fputs("\n\trts\n\n\tend\n",out);
fclose(out);
if(loops != 0) break;
p = (char *) *varargs;
loops = 3;
if(mode & DEBUG) printf("Searching function `%s' in vargs table...\n", functionp);
if(p != NULL)
{
if(mode & VARGSLOGIC)
{
int fnlen = strlen(functionp);
if((fnlen > 7) && (!strcmp(functionp + fnlen - 7, "TagList")))
{
/* xxxTagList function found. Make xxxTags of it
*/
strncpy(tmpfuncnam, functionp, fnlen - 4);
strcpy (tmpfuncnam + fnlen - 4, "s" );
functionp = tmpfuncnam;
loops = 0;
}
else if((fnlen > 1) && ((functionp[fnlen-1] == 'A') && (functionp[fnlen-2] >= 'a') && (functionp[fnlen-2] <= 'z')))
{
/* Not that smart recognition... But you probably
** don't want to have a function CreateDA() varargs,
** want you?
**
** Recognized are functions that end with 'A' and that
** have a lowercase letter before that.
*/
strcpy(tmpfuncnam, functionp);
tmpfuncnam[fnlen-1] = '\0';
functionp = tmpfuncnam;
loops = 0;
}
if(!loops)
{
if(mode & DEBUG) puts("Found via internal logic!");
}
}
if(loops) for(i=0; p != NULL; i+=2)
{
if(!strcmp(p, functionp))
{
if(mode & DEBUG) puts("Found!");
functionp = (char *) varargs[i - 1]; /* [i+1] */
loops = 0;
break;
}
/*i += 2;*/
p = (char *) varargs[i];
}
}
}
offset += 6;
} /* for(;;) */
if(name) fclose(fd);
fputs("\n\tend\n", lvos);
fclose(lvos);
}
/* Append '/' to path if needed
*/
static void fillpath(char *dirpath)
{
int sl = strlen(dirpath);
switch(dirpath[sl-1])
{
case ':': /* ':' should be AMIGA-only! This will be commented out. */
case '/':
break;
default:
strcpy(dirpath+sl, "/");
break;
}
}
/* Show program usage
*/
static void Usage(const char *) NORETURN;
static void Usage(const char *myname)
{
printf("fd2lib 1.5 (c) by Volker Barthelmann / "
"Johnny Teveßen / Frank Wille\n\n"
" -- Caution: Needs ~5000 byte stack! --\n"
"\n"
"Usage : %s [-sc] [-sd] [-40] [-on] [-nv] [-o <dir>] [-of <format>]\n"
" [-d] [-?|--help] [files/pattern]\n"
"\n"
" -sc : Use small code model (else large code model)\n"
" -sd : Use small data model (else large data model)\n"
" -40 : Use fast call model for 68040\'s (no 'movem's)\n"
" -on : Use old motorola assembler notation\n"
" -nv : No varargs logic - ...A and ...TagList will not be detected\n"
" -o : Specify directory to store source files in\n"
" -of : C printf style output format to generate compiling\n"
" script. Three `%%s' are replaced with output file name\n"
" -d : Turn on debugging/verbose mode\n"
" -? : Show help/version and quit\n"
"files : FD files to convert, defaults to stdin\n"
"\n"
"Commandline is parsed left-to-right. Specifying\n"
"\"alib_lib.fd -sd blib_lib.fd\" will result in alib\n"
"getting large data model.\n",
myname
);
exit(0);
}
/* Remember: ixemul.library does command line expansion, eg.:
**
** redrose# fd2lib -sc -sd /fd/a*_lib.fd
**
** will become:
**
** redrose# fd2lib -sc -sd /fd/amigaguide_lib.fd /fd/asl_lib.fd ...
**
*/
int main(int argc, char **argv)
{
int erg = 0 /*EXIT_FAILURE*/;
int mode = NEWNOTATE | VARGSLOGIC;
int filesdone = 0;
char outdir[80] = "", outform[250] = "";
if(argc > 1)
{
int i;
for(i=1; i<argc; i++)
{
if(argv[i][0] == '-')
{
/* Parse option */
if( !strcmp(argv[i], "-sc")) mode |= SMALLCODE;
else if( !strcmp(argv[i], "-sd")) mode |= SMALLDATA;
else if( !strcmp(argv[i], "-40")) mode |= FASTCALL;
else if( !strcmp(argv[i], "-on")) mode &= ~NEWNOTATE;
else if( !strcmp(argv[i], "-nv")) mode &= ~VARGSLOGIC;
else if( !strcmp(argv[i], "-pr")) clibname=argv[++i];
else if( !strcmp(argv[i], "-o" ))
{
if(i < (argc-1))
{
i ++;
if(strlen(argv[i]) < sizeof(outdir))
{
strcpy (outdir, argv[i]);
fillpath(outdir);
}
else
{
fprintf(stderr, "Path too long. Maximum is %lu characters. "
"Ignored.\n", (unsigned long)sizeof(outdir));
}
}
else
{
fputs("No path specified after `-o'!\n", stderr);
}
}
else if( !strcmp(argv[i], "-of"))
{
if(i < (argc-1))
{
i ++;
if(strlen(argv[i]) < sizeof(outform))
{
strcpy(outform, argv[i]);
strcat(outform, "\n" );
}
else
{
fprintf(stderr, "Format too long. Maximum is %lu characters. "
"Ignored.\n", (unsigned long)sizeof(outform));
}
}
else
{
fputs("No format specified after `-of'!\n", stderr);
}
}
else if( !strcmp(argv[i], "-d" )) mode |= DEBUG;
else if((!strcmp(argv[i], "-?" )) ||
(!strcmp(argv[i], "--help"))) Usage(*argv);
else
{
fprintf(stderr, "Unknown option `%s'\n\n", argv[i]);
Usage(*argv);
}
}
else
{
/* Process file */
if(argv[i][0] == '?') Usage(*argv);
else
{
if(clibname){
FILE *file=fopen(clibname,"r");
size_t size;
if(!file){
fprintf(stderr, "Couldn't open <%s>!\n",clibname);
exit(EXIT_FAILURE);
}
if(fseek(file,0,SEEK_END)) exit(EXIT_FAILURE);
size=ftell(file);
if(fseek(file,0,SEEK_SET)) exit(EXIT_FAILURE);
clibtext=malloc(size+1);
if(!clibtext){
fprintf(stderr,"Out of memory!\n");
exit(EXIT_FAILURE);
}
clibtext[fread(clibtext,1,size,file)]=0;
fclose(file);
}
ProcessFD(argv[i], mode, outdir, outform);
if(clibname){
free(clibtext);
clibname=clibtext=0;
}
filesdone ++;
}
}
}
}
if(!filesdone) ProcessFD(NULL, mode, outdir, outform);
return(erg);
}